use super::*;

/// A [Class Definition Table](
/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table).
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy)]
pub enum ClassDefinition<'a> {
	Format1 { start: GlyphId, classes: LazyArray16<'a, u16> },
	Format2 { records: LazyArray16<'a, RangeRecord> },
	Empty,
}
impl<'a> FromSlice<'a> for ClassDefinition<'a> {
	#[inline]
	fn parse(data: &'a [u8]) -> Option<Self> {
		let mut s = Stream::new(data);
		match s.read::<u16>()? {
			1 => Some(Self::Format1 {
				start: s.read::<GlyphId>()?,
				classes: s.parse_array16()?,
			}),
			2 => Some(Self::Format2 {
				records: s.parse_array16()?,
			}),
			_ => None,
		}
	}
}
impl<'a> ClassDefinition<'a> {
	/// Returns the glyph class of the glyph (zero if it is not defined).
	pub fn get(&self, glyph: GlyphId) -> u16 {
		match self {
			Self::Format1 { start, classes } => glyph.0.checked_sub(start.0).and_then(|index| classes.get(index)),
			Self::Format2 { records } => records.range(glyph).map(|record| record.value),
			Self::Empty => Some(0),
		}
		.unwrap_or(0)
	}
}
impl<'a> IntoIterator for ClassDefinition<'a> {
	type Item = (u16, GlyphId, GlyphId);
	type IntoIter = ClassDefinitionIter<'a>;
	fn into_iter(self) -> Self::IntoIter {
		ClassDefinitionIter { defs: self, next: 0 }
	}
}
pub struct ClassDefinitionIter<'a> {
	defs: ClassDefinition<'a>,
	next: u16,
}
impl<'a> Iterator for ClassDefinitionIter<'a> {
	type Item = (u16, GlyphId, GlyphId);
	fn next(&mut self) -> Option<Self::Item> {
		match &self.defs {
			ClassDefinition::Format1 { start, classes } => {
				let cls = classes.get(self.next)?;
				let id = GlyphId(start.0 + self.next);
				self.next += 1;
				return Some((cls, id, id));
			}
			ClassDefinition::Format2 { records } => {
				let r = records.get(self.next)?;
				self.next += 1;
				return Some((r.value, r.start, r.end));
			}
			ClassDefinition::Empty => return None,
		}
	}
}
